package jnpf.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.text.StrPool;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jnpf.base.service.SysconfigService;
import jnpf.config.JnpfOauthConfig;
import jnpf.consts.LoginTicketStatus;
import jnpf.granter.TokenGranterBuilder;
import jnpf.model.LoginConfigModel;
import jnpf.model.LoginModel;
import jnpf.permission.controller.SocialsUserController;
import jnpf.permission.model.socails.SocialsUserVo;
import jnpf.permission.service.UserService;
import jnpf.service.AuthService;
import jnpf.base.ActionResult;
import jnpf.base.NoDataSourceBind;
import jnpf.base.UserInfo;
import jnpf.config.ConfigValueUtil;
import jnpf.model.LoginTicketModel;
import jnpf.model.BaseSystemInfo;
import jnpf.model.login.PcUserVO;
import jnpf.permission.entity.UserEntity;
import jnpf.exception.LoginException;
import jnpf.model.login.LoginForm;
import jnpf.model.login.LoginVO;
import jnpf.service.LoginService;
import jnpf.util.*;
import jnpf.util.data.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static jnpf.consts.AuthConsts.PARAMS_JNPF_TICKET;

/**
 * 登录控制器
 *
 * @author JNPF开发平台组
 * @version V3.1.0
 * @copyright 引迈信息技术有限公司
 * @date 2019年9月26日 上午9:18
 */
@Api(tags = "登陆数据", value = "oauth")
@Slf4j
@RestController
@RequestMapping("/api/oauth")
public class LoginController {

    @Autowired
    private UserService userApi;
    @Autowired
    private LoginService loginService;
    @Autowired
    private AuthService authService;
    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private JnpfOauthConfig oauthConfig;
    @Autowired
    private SysconfigService sysConfigApi;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private TokenGranterBuilder tokenGranterBuilder;
    @Autowired
    private SocialsUserController socialsUserApi;

    @ApiOperation("登陆")
    @RequestMapping(value = "/Login/**", method = {RequestMethod.GET, RequestMethod.POST})
    public ActionResult<LoginVO> login(@RequestParam Map<String, String> parameters) throws LoginException {
        return authService.login(parameters);
    }


    /**
     * 验证密码
     *
     * @return
     */
    @ApiOperation("锁屏解锁登录")
    @PostMapping("/LockScreen")
    public ActionResult lockScreen(@RequestBody LoginForm loginForm) throws LoginException {
        UserEntity userEntity = userApi.getUserByAccount(loginForm.getAccount());
        if (userEntity == null) {
            UserInfo userInfo = UserProvider.getUser();
            if(userInfo.getUserId() != null){
                UserProvider.logoutByUserId(userInfo.getUserId());
            }
            throw new LoginException("账号不存在");
        }
        if (!Md5Util.getStringMd5(loginForm.getPassword().toLowerCase() + userEntity.getSecretkey().toLowerCase()).equals(userEntity.getPassword())) {
            throw new LoginException("账户或密码错误，请重新输入。");
        }
        return ActionResult.success("验证成功");
    }

    /**
     * 登录注销
     *
     * @return
     */
    @NoDataSourceBind
    @ApiOperation("退出")
    @RequestMapping(value = {"/Logout","/Logout/{grandtype}" }, method = {RequestMethod.GET, RequestMethod.POST})
    public ActionResult logout(@PathVariable(value = "grandtype", required = false) String grandtype) {
        return tokenGranterBuilder.getGranterByLogin(grandtype).logout();
    }

    /**
     * 踢出指定用户, 推送Websocket用户被强制下线
     * @param tokens
     */
    @NoDataSourceBind
    @ApiOperation("踢出指定用户")
    @PostMapping(value = {"/KickoutToken" })
    public void kickoutByToken(@RequestParam(value = "tokens", required = false) String[] tokens, @RequestParam(name = "userId", required = false) String userId, @RequestParam(name = "tenantId", required = false) String tenantId) {
        if(StringUtil.isNotEmpty(tokens)) {
            authService.kickoutByToken(tokens);
        }else{
            authService.kickoutByUserId(userId, tenantId);
        }
    }

    /**
     * 获取用户登录信息
     *
     * @return
     */
    @ApiOperation("获取用户登录信息")
    @GetMapping("/CurrentUser")
    public ActionResult<PcUserVO> currentUser(String type) throws LoginException {
        if (StringUtil.isEmpty(type)) {
            type = "Web";
        } else {
            type = "App";
        }
        PcUserVO pcUserVO = loginService.getCurrentUser(type);
        if (pcUserVO == null) {
            throw new LoginException("账户异常");
        }
        return ActionResult.success(pcUserVO);
    }

    /**
     * 图形验证码
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("图形验证码")
    @GetMapping("/ImageCode/{codeLength}/{timestamp}")
    public void imageCode(@PathVariable("codeLength") Integer codeLength, @PathVariable("timestamp") String timestamp) {
        DownUtil.downCode(codeLength);
        redisUtil.insert(timestamp, ServletUtil.getSession().getAttribute(CodeUtil.RANDOMCODEKEY), 300);
    }

    /**
     * 注销用户
     *
     * @return
     */
    @ApiOperation("注销用户")
    @PostMapping("/logoutCurrentUser")
    public ActionResult logoutCurrentUser() {
        UserInfo userInfo = UserProvider.getUser();
        if (userInfo.getIsAdministrator() != null && UserProvider.getUser().getIsAdministrator()) {
            return ActionResult.fail("管理员不能注销");
        }
        if (userInfo.getIsAdministrator() != null) {
            if (!userInfo.getIsAdministrator()) {
                userApi.delete(userApi.getInfo(userInfo.getUserId()));
                UserProvider.kickoutByUserId(userInfo.getUserId(), DataSourceContextHolder.getDatasourceId());
            }
        }
        return ActionResult.success("注销成功");
    }

    /**
     * 判断是否需要验证码
     *
     * @param account 账号
     */
    @NoDataSourceBind()
    @ApiOperation("判断是否需要验证码")
    @GetMapping("/getConfig/{account}")
    public ActionResult check(@PathVariable("account") String account) throws LoginException {
        LoginModel loginModel = new LoginModel();
        String tenantId = "0";
        String tenantDbConnectionString = "0";
        if (configValueUtil.isMultiTenancy()) {
            LoginForm loginForm = new LoginForm();
            loginForm.setAccount(account);
            UserInfo userInfo = new UserInfo();
            userInfo.setUserAccount(loginForm.getAccount());
            userInfo = loginService.getTenantAccount(userInfo);
            tenantId = userInfo.getTenantId();
            tenantDbConnectionString = userInfo.getTenantDbConnectionString();
        }
        // 获取配置
        BaseSystemInfo sysConfigInfo = sysConfigApi.getSysInfo();
        // 是否开启验证码
        if (Objects.nonNull(sysConfigInfo) && "1".equals(String.valueOf(sysConfigInfo.getEnableVerificationCode()))) {
            loginModel.setEnableVerificationCode(1);
            Integer verificationCodeNumber = sysConfigInfo.getVerificationCodeNumber();
            loginModel.setVerificationCodeNumber(verificationCodeNumber == null ? 4 : verificationCodeNumber);
            return ActionResult.success(loginModel);
        }
        loginModel.setEnableVerificationCode(0);
        return ActionResult.success(loginModel);
    }

    /**
     * 获取登录配置, 是否需要跳转、第三方登录信息
     * @return {re}
     * @throws LoginException
     */
    @NoDataSourceBind()
    @ApiOperation("获取登录配置")
    @GetMapping("/getLoginConfig")
    public ActionResult<LoginConfigModel> getLoginConfig() {
        LoginConfigModel loginConfigModel = new LoginConfigModel();
        if(oauthConfig.getSsoEnabled()){
            String url = oauthConfig.getLoginPath() + StrPool.SLASH + oauthConfig.getDefaultSSO();
            loginConfigModel.setRedirect(true);
            loginConfigModel.setUrl(url);
            loginConfigModel.setTicketParams(PARAMS_JNPF_TICKET);
        } else {
            //追加第三方登录配置
            List<SocialsUserVo> loginList = socialsUserApi.getLoginList(PARAMS_JNPF_TICKET.toUpperCase());
            if (CollectionUtil.isNotEmpty(loginList)) {
                loginConfigModel.setSocialsList(loginList);
                loginConfigModel.setRedirect(false);
                loginConfigModel.setTicketParams(PARAMS_JNPF_TICKET);
            }
        }
        return ActionResult.success(loginConfigModel);
    }


    /**
     * 获取登录票据
     * @return {msg:有效期, data:票据}
     */
    @NoDataSourceBind()
    @ApiOperation("获取登录票据")
    @GetMapping("/getTicket")
    public ActionResult<String> getTicket() {
        LoginTicketModel ticketModel = new LoginTicketModel();
        ticketModel.setTicketTimeout(System.currentTimeMillis() + oauthConfig.getTicketTimeout()*1000);
        String ticket = TicketUtil.createTicket(ticketModel, oauthConfig.getTicketTimeout());
        return ActionResult.success(ticketModel.getTicketTimeout().toString(), ticket);
    }

    /**
     * 检测票据登录状态
     * @return {re}
     * @throws LoginException
     */
    @NoDataSourceBind()
    @ApiOperation("获取登录状态")
    @GetMapping("/getTicketStatus/{ticket}")
    public ActionResult<LoginTicketModel> getTicketStatus(@PathVariable("ticket") String ticket) {
        LoginTicketModel ticketModel = TicketUtil.parseTicket(ticket);
        if(ticketModel == null){
            ticketModel = new LoginTicketModel().setStatus(LoginTicketStatus.Invalid.getStatus()).setValue("票据失效！");
        }else {
            if (ticketModel.getStatus() != LoginTicketStatus.UnLogin.getStatus()&&ticketModel.getStatus() != LoginTicketStatus.UnBind.getStatus()) {
                TicketUtil.deleteTicket(ticket);
            }
        }
        return ActionResult.success(ticketModel);
    }

}
